package com.ssy.lingxi.order.serviceimpl.mobile;

import com.querydsl.core.group.GroupBy;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.PlatformRuleTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderTradeProcessTypeEnum;
import com.ssy.lingxi.common.constant.order.OrderTypeEnum;
import com.ssy.lingxi.common.constant.pay.BalanceTypeEnum;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.*;
import com.ssy.lingxi.order.model.constant.OrderOuterStatusEnum;
import com.ssy.lingxi.order.model.dto.MemberLogoDTO;
import com.ssy.lingxi.order.model.vo.basic.request.OrderIdVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderRuleVO;
import com.ssy.lingxi.order.model.vo.common.request.OrderProductHistoryVO;
import com.ssy.lingxi.order.model.vo.common.response.MobileOrderProductHistoryQueryVO;
import com.ssy.lingxi.order.model.vo.common.response.OrderAfterSalePaymentDetailVO;
import com.ssy.lingxi.order.model.vo.mobile.request.MobileOrderAfterSaleVO;
import com.ssy.lingxi.order.model.vo.mobile.response.MobileAfterSalePageQueryVO;
import com.ssy.lingxi.order.model.vo.mobile.response.MobileAfterSaleProductDetailVO;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.feign.IMemberFeignService;
import com.ssy.lingxi.order.service.mobile.IMobileOrderCommonService;
import com.ssy.lingxi.order.service.web.IOrderCommonService;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * App - 订单其他相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-09-26
 */
@Service
public class MobileOrderCommonServiceImpl implements IMobileOrderCommonService {
    @Resource
    private IBaseCacheService baseCacheService;

    @Resource
    private IOrderCommonService orderCommonService;

    @Resource
    private IMemberFeignService memberFeignService;

    @Resource
    private JPAQueryFactory jpaQueryFactory;

    /**
     * “商品详情” - 分页查询商品交易记录
     *
     * @param headers   Http头部信息
     * @param historyVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<MobileOrderProductHistoryQueryVO>> pageOrderProductHistories(HttpHeaders headers, OrderProductHistoryVO historyVO) {
        baseCacheService.checkMobileRequestHeader(headers);

        QOrderProductHistoryDO qOrderProductHistory = QOrderProductHistoryDO.orderProductHistoryDO;
        JPAQuery<MobileOrderProductHistoryQueryVO> query = jpaQueryFactory.select(Projections.constructor(MobileOrderProductHistoryQueryVO.class, qOrderProductHistory.createTime, qOrderProductHistory.buyerMemberId, qOrderProductHistory.buyerMemberName, qOrderProductHistory.quantity, qOrderProductHistory.unit))
                .from(qOrderProductHistory)
                .where(qOrderProductHistory.shopId.eq(historyVO.getShopId()).and(qOrderProductHistory.productId.eq(historyVO.getProductId())))
                .orderBy(qOrderProductHistory.id.desc());

        long totalCount = query.fetchCount();

        //从会员服务查询采购商Logo
        List<MobileOrderProductHistoryQueryVO> result = query.limit(historyVO.getPageSize()).offset(historyVO.getCurrentOffset()).fetch();
        if(!CollectionUtils.isEmpty(result)) {
            List<Long> buyerMemberIds = result.stream().map(MobileOrderProductHistoryQueryVO::getBuyerMemberId).distinct().collect(Collectors.toList());
            Wrapper<List<MemberLogoDTO>> logoResult = memberFeignService.findMemberLogos(buyerMemberIds);
            if(logoResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(logoResult.getCode(), logoResult.getMessage());
            }

            result = result.stream().peek(queryVO -> logoResult.getData().stream().filter(r -> r.getMemberId().equals(queryVO.getBuyerMemberId())).findFirst().ifPresent(r -> queryVO.setLogo(r.getLogo()))).collect(Collectors.toList());
        }

        return Wrapper.success(new PageData<>(totalCount, result));
    }

    /**
     * “申请售后” - 查询订单商品信息
     *
     * @param headers     Http头部信息
     * @param afterSaleVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<MobileAfterSalePageQueryVO> findAfterSaleOrder(HttpHeaders headers, MobileOrderAfterSaleVO afterSaleVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromMobile(headers);
        QOrderDO qOrder = QOrderDO.orderDO;
        OrderDO order = jpaQueryFactory.select(qOrder).from(qOrder).where(qOrder.id.eq(afterSaleVO.getOrderId())).fetchFirst();
        if(order == null || !order.getBuyerMemberId().equals(loginUser.getMemberId()) || !order.getBuyerRoleId().equals(loginUser.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.ORDER_DOES_NOT_EXIST);
        }

        OrderTypeEnum orderType = OrderTypeEnum.parse(order.getOrderType());
        if(orderType == null) {
            return Wrapper.fail(ResponseCode.ORDER_TYPE_DOES_NOT_EXIST);
        }

        // （App额外规则）订单类型为积分兑换或渠道积分兑换的隐藏退货与维修二类售后
        if((orderType.equals(OrderTypeEnum.CREDITS_EXCHANGE) || orderType.equals(OrderTypeEnum.CHANNEL_POINT_EXCHANGE)) && (afterSaleVO.getAfterSalesType().equals(3) || afterSaleVO.getAfterSalesType().equals(4))) {
            return Wrapper.success(null);
        }

        //Step 2: 规则
        // 2-1. 查询采购订单中选择的供应会员的订单数据，根据选择的售后订单类型进行筛选，只显示已收到第一批货之后的订单且当前订单外部状态不是待确认支付结果
        // 2-2. 如果订单类型为现货采购、询价采购、集采、积分兑换、渠道直采、渠道现货、渠道积分兑换，
        //      查询交易流程规则配置中流程类型为售后换货流程的工作流
        // 2-3. 如果订单类型为采购询价合同、采购竞价合同、采购招标合同只允许选择合同编号相同的订单，
        //      查询采购流程规则配置的流程类型为售后换货流程的适用当前合同的工作流

        //Step 3: 在IOrderCommonService中有个类似的接口，如这里修改了则要做相应的修改
        switch (orderType) {
            case SPOT_PURCHASING:
            case INQUIRY_TO_PURCHASE:
            case COLLECTIVE_PURCHASE:
            case CHANNEL_STRAIGHT_MINING:
            case CHANNEL_SPOT:
            case CREDITS_EXCHANGE:
            case CHANNEL_POINT_EXCHANGE:
                return pageAfterSaleOrdersByTradeProcess(afterSaleVO.getOrderId(), afterSaleVO.getAfterSalesType(), afterSaleVO.getShopId());
            case QUERY_PRICE_CONTRACT:
            case PRICE_COMPETITION_CONTRACT_PURCHASE:
            case PURCHASE_CONTRACT_BIDDING:
            case REQUISITION_TO_PURCHASE:
                return pageAfterSaleOrdersByPurchaseProcess(afterSaleVO.getOrderId(), afterSaleVO.getAfterSalesType());
            default:
                return Wrapper.success(null);
        }
    }

    /**
     * 售后能力 - 查询已经确认支付结果的支付记录列表
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<List<OrderAfterSalePaymentDetailVO>> findAfterSaleOrderPayments(HttpHeaders headers, OrderIdVO idVO) {
        baseCacheService.needLoginFromMobile(headers);
        return orderCommonService.findAfterSaleOrderPayments(idVO);
    }

    /**
     * “店铺会员” - 查询平台账户余额类型是否启用
     *
     * @param headers HttpHeaders信息
     * @return 查询结果
     */
    @Override
    public Wrapper<OrderRuleVO> findPlatformBalanceTypeStatus(HttpHeaders headers) {
        baseCacheService.needLoginFromMobile(headers);
        QBaseOrderRuleDO qBaseOrderRule = QBaseOrderRuleDO.baseOrderRuleDO;
        BaseOrderRuleDO baseOrderRule = jpaQueryFactory.select(qBaseOrderRule).from(qBaseOrderRule)
                .where(qBaseOrderRule.ruleType.eq(PlatformRuleTypeEnum.BALANCE_TYPE.getCode()).and(qBaseOrderRule.methodCode.eq(BalanceTypeEnum.PLATFORM.getCode())))
                .fetchFirst();
        return Wrapper.success(baseOrderRule == null ? new OrderRuleVO(PlatformRuleTypeEnum.BALANCE_TYPE.getCode(), BalanceTypeEnum.PLATFORM.getCode(), EnableDisableStatus.DISABLE.getCode()) : new OrderRuleVO(baseOrderRule.getRuleType(), baseOrderRule.getMethodCode(), baseOrderRule.getStatus()));
    }

    /**
     * 根据交易流程规则配置查询售后订单
     * @param orderId        订单Id
     * @param afterSalesType 售后类型，前端接口参数中定义的枚举，要和交易流程类型枚举一致
     * @param shopId         App商城Id
     * @return               查询结果
     */
    private Wrapper<MobileAfterSalePageQueryVO> pageAfterSaleOrdersByTradeProcess(Long orderId, Integer afterSalesType, Long shopId) {
        QOrderDO qOrder = QOrderDO.orderDO;
        QOrderProductDO qOrderProduct = QOrderProductDO.orderProductDO;
        QOrderMaterialDO qOrderMaterial = QOrderMaterialDO.orderMaterialDO;
        QOrderContractDO qOrderContract = QOrderContractDO.orderContractDO;
        QOrderTradeProcessDO qOrderTradeProcess = QOrderTradeProcessDO.orderTradeProcessDO;
        QOrderTradeProcessProductDO qOrderTradeProcessProduct = QOrderTradeProcessProductDO.orderTradeProcessProductDO;

        //Step 1: 定义关联关系，OrderDO表必须要有distinct()
        // ShopId要以App商城Id为主，即售后从哪个商城发起，就查询哪个商城的交易流程规则配置
        JPAQuery<?> query = jpaQueryFactory.from(qOrder).distinct()
                .leftJoin(qOrderProduct).on(qOrder.id.eq(qOrderProduct.order.id))
                .leftJoin(qOrderMaterial).on(qOrderProduct.id.eq(qOrderMaterial.orderProduct.id))
                .leftJoin(qOrderContract).on(qOrder.id.eq(qOrderContract.order.id))
                .leftJoin(qOrderTradeProcess).on(qOrder.vendorMemberId.eq(qOrderTradeProcess.memberId).and(qOrder.vendorRoleId.eq(qOrderTradeProcess.roleId)))
                .leftJoin(qOrderTradeProcessProduct).on(qOrderTradeProcess.id.eq(qOrderTradeProcessProduct.process.id))
                .where(qOrder.id.eq(orderId).and(qOrderTradeProcess.shopId.eq(shopId)));

        //Step 2: 固定的查询条件
        //只可选择已退货数量小于订单数量的订单商品
        query.where(qOrderProduct.returnCount.lt(qOrderProduct.quantity));

        //订单状态：
        //换货：只显示已收到第一批货之后的订单且当前订单外部状态不是待确认支付结果
        //退货：只显示已发过第一批货之后、或已经支付成功过一次的订单且当前订单外部状态不是待确认支付结果，且订单状态不是已中止
        //维修：只显示已收到第一批货之后的订单
        if(afterSalesType.equals(OrderTradeProcessTypeEnum.AFTER_SALES_EXCHANGES.getCode())) {
            query.where(qOrder.hasReceived.isTrue().and(qOrder.outerStatus.ne(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode())));
        } else if(afterSalesType.equals(OrderTradeProcessTypeEnum.AFTER_SALES_RETURNS.getCode())) {
            query.where(qOrder.hasDelivered.isTrue().or(qOrder.hasPaid.isTrue()));
            query.where(qOrder.outerStatus.ne(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode()).and(qOrder.outerStatus.ne(OrderOuterStatusEnum.TERMINATED.getCode())));
        } else {
            query.where(qOrder.hasReceived.isTrue());
        }

        //流程类型、状态
        query.where(qOrderTradeProcess.processType.eq(afterSalesType).and(qOrderTradeProcess.status.eq(EnableDisableStatus.ENABLE.getCode())));
        //流程规则配置
        query.where(qOrderTradeProcess.allProducts.isTrue().or(qOrderTradeProcessProduct.productId.eq(qOrderProduct.productId).and(qOrderTradeProcessProduct.skuId.eq(qOrderProduct.skuId))));

        //Step 5: 使用transform()对结果进行聚合统计，并通过Projections.Constructor到VO对象
        Map<Long, MobileAfterSalePageQueryVO> transform = query.transform(GroupBy.groupBy(qOrder.id).as(
                Projections.constructor(MobileAfterSalePageQueryVO.class, qOrder.shopId, qOrder.id, qOrder.orderNo, qOrder.digest, qOrder.vendorMemberId, qOrder.vendorRoleId, qOrder.vendorMemberName, qOrder.vendorLogo, qOrder.orderType, qOrder.createTime, qOrder.outerStatus, qOrderContract.contractId, qOrderContract.contractNo,
                        GroupBy.list(Projections.constructor(MobileAfterSaleProductDetailVO.class,
                                qOrderProduct.id,
                                qOrder.orderType,
                                qOrderTradeProcess.processKey,
                                qOrderProduct.logo,
                                qOrderProduct.skuId,
                                qOrderProduct.productNo,
                                qOrderProduct.name,
                                qOrderProduct.category,
                                qOrderProduct.brand,
                                qOrderProduct.unit,
                                qOrderProduct.spec,
                                qOrderProduct.quantity,
                                qOrderProduct.refPrice,
                                qOrderProduct.amount,
                                qOrderProduct.paidAmount,
                                qOrderProduct.exchangeCount,
                                qOrderProduct.returnCount,
                                qOrderProduct.maintainCount,
                                qOrderProduct.returnAmount,
                                qOrderProduct.tax,
                                qOrderProduct.taxRate,
                                qOrderProduct.priceType,
                                qOrderMaterial.skuId,
                                qOrderMaterial.productNo,
                                qOrderMaterial.name,
                                qOrderMaterial.category,
                                qOrderMaterial.brand,
                                qOrderMaterial.spec
                        )))));

        return Wrapper.success(transform.getOrDefault(orderId, null));
    }

    /**
     * 根据采购流程规则配置查询售后订单
     * @param orderId         订单Id
     * @param afterSalesType  售后类型，前端接口参数中定义的枚举，要和采购流程类型枚举一致
     * @return               查询结果
     */
    private Wrapper<MobileAfterSalePageQueryVO> pageAfterSaleOrdersByPurchaseProcess(Long orderId, Integer afterSalesType) {
        QOrderDO qOrder = QOrderDO.orderDO;
        QOrderProductDO qOrderProduct = QOrderProductDO.orderProductDO;
        QOrderMaterialDO qOrderMaterial = QOrderMaterialDO.orderMaterialDO;
        QOrderContractDO qOrderContract = QOrderContractDO.orderContractDO;
        QOrderPurchaseProcessDO qOrderPurchaseProcess = QOrderPurchaseProcessDO.orderPurchaseProcessDO;
        QOrderPurchaseProcessContractDO qOrderPurchaseProcessContract = QOrderPurchaseProcessContractDO.orderPurchaseProcessContractDO;

        //Step 1: 定义关联关系，OrderDO表必须要有distinct()
        JPAQuery<?> query = jpaQueryFactory.from(qOrder).distinct()
                .leftJoin(qOrderProduct).on(qOrder.id.eq(qOrderProduct.order.id))
                .leftJoin(qOrderMaterial).on(qOrderProduct.id.eq(qOrderMaterial.orderProduct.id))
                .leftJoin(qOrderContract).on(qOrder.id.eq(qOrderContract.order.id))
                .leftJoin(qOrderPurchaseProcess).on(qOrder.buyerMemberId.eq(qOrderPurchaseProcess.memberId).and(qOrder.buyerRoleId.eq(qOrderPurchaseProcess.roleId)))
                .leftJoin(qOrderPurchaseProcessContract).on(qOrderPurchaseProcess.id.eq(qOrderPurchaseProcessContract.process.id))
                .where(qOrder.id.eq(orderId));

        //Step 2: 固定的查询条件
        //只可选择已退货数量小于订单数量的订单商品
        query.where(qOrderProduct.returnCount.lt(qOrderProduct.quantity));

        //订单状态：
        //换货：只显示已收到第一批货之后的订单且当前订单外部状态不是待确认支付结果
        //退货：只显示已发过第一批货之后、或已经支付成功过一次的订单且当前订单外部状态不是待确认支付结果，且订单状态不是已中止
        //维修：只显示已收到第一批货之后的订单
        if(afterSalesType.equals(OrderTradeProcessTypeEnum.AFTER_SALES_EXCHANGES.getCode())) {
            query.where(qOrder.hasReceived.isTrue().and(qOrder.outerStatus.ne(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode())));
        } else if(afterSalesType.equals(OrderTradeProcessTypeEnum.AFTER_SALES_RETURNS.getCode())) {
            query.where(qOrder.hasDelivered.isTrue().or(qOrder.hasPaid.isTrue()));
            query.where(qOrder.outerStatus.ne(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode()).and(qOrder.outerStatus.ne(OrderOuterStatusEnum.TERMINATED.getCode())));
        } else {
            query.where(qOrder.hasReceived.isTrue());
        }

        //流程类型、状态
        query.where(qOrderPurchaseProcess.processType.eq(afterSalesType).and(qOrderPurchaseProcess.status.eq(EnableDisableStatus.ENABLE.getCode())));
        //流程规则配置
        query.where(qOrderPurchaseProcess.allContracts.isTrue().or(qOrderPurchaseProcessContract.contractId.eq(qOrderContract.contractId)));

        //Step 5: 使用transform()对结果进行聚合统计，并通过Projections.Constructor到VO对象
        Map<Long, MobileAfterSalePageQueryVO> transform = query.transform(GroupBy.groupBy(qOrder.id).as(
                Projections.constructor(MobileAfterSalePageQueryVO.class, qOrder.shopId, qOrder.id, qOrder.orderNo, qOrder.digest, qOrder.vendorMemberId, qOrder.vendorRoleId, qOrder.vendorMemberName, qOrder.vendorLogo, qOrder.orderType, qOrder.createTime, qOrder.outerStatus, qOrderContract.contractId, qOrderContract.contractNo,
                        GroupBy.list(Projections.constructor(MobileAfterSaleProductDetailVO.class,
                                qOrderProduct.id,
                                qOrder.orderType,
                                qOrderPurchaseProcess.processKey,
                                qOrderProduct.logo,
                                qOrderProduct.skuId,
                                qOrderProduct.productNo,
                                qOrderProduct.name,
                                qOrderProduct.category,
                                qOrderProduct.brand,
                                qOrderProduct.unit,
                                qOrderProduct.spec,
                                qOrderProduct.quantity,
                                qOrderProduct.refPrice,
                                qOrderProduct.amount,
                                qOrderProduct.paidAmount,
                                qOrderProduct.exchangeCount,
                                qOrderProduct.returnCount,
                                qOrderProduct.maintainCount,
                                qOrderProduct.returnAmount,
                                qOrderProduct.tax,
                                qOrderProduct.taxRate,
                                qOrderProduct.priceType,
                                qOrderMaterial.skuId,
                                qOrderMaterial.productNo,
                                qOrderMaterial.name,
                                qOrderMaterial.category,
                                qOrderMaterial.brand,
                                qOrderMaterial.spec
                        )))));

        return Wrapper.success(transform.getOrDefault(orderId, null));
    }
}
